{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 校准 $\\pi$ 脉冲\n",
    "*版权所有 (c) 2021 百度量子计算研究所，保留所有权利。*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 内容概要\n",
    "本教程介绍如何通过改变驱动脉冲的振幅来校准 $\\pi$ 脉冲。本教程的大纲如下：\n",
    "\n",
    "- 背景介绍\n",
    "- 准备工作\n",
    "- 定义系统哈密顿量\n",
    "- 振幅扫描\n",
    "- 余弦拟合\n",
    "- 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 背景介绍\n",
    "\n",
    "校准 $\\pi$ 脉冲是量子计算中最基本的操作之一。这是因为要实现 X 门，我们需要在 X 通道上输入一个 $\\pi$ 脉冲。此外，校准 $\\pi$ 脉冲在校准实际硬件方面也起着重要作用。因此，本教程将演示如何使用量脉校准 $\\pi$ 脉冲。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备工作\n",
    "\n",
    "成功安装量脉后，您可以按照本教程运行下面的量脉程序。在运行此教程前，您需要从量脉（Quanlse）和其它常用的 Python 库导入以下包："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the Hamiltonian module\n",
    "from Quanlse.QHamiltonian import QHamiltonian as QHam \n",
    "\n",
    "# Import related packages\n",
    "from Quanlse.QOperator import duff, driveX\n",
    "from Quanlse.QWaveform import gaussian, QJob, QJobList\n",
    "\n",
    "# Import simulator interface for Quanlse Cloud Service\n",
    "from Quanlse.remoteSimulator import remoteSimulatorRunHamiltonian as runHamiltonian\n",
    "\n",
    "# Import numpy\n",
    "from numpy import linspace, pi, dot, array, cos\n",
    "\n",
    "# Import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Import curve_fit function from scipy\n",
    "from scipy.optimize import curve_fit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义系统哈密顿量\n",
    "\n",
    "在量子控制领域，我们经常用哈密顿量来描述一个量子系统。一般来说，系统哈密顿量由含时和不含时项组成：\n",
    "\n",
    "$$\n",
    "\\hat{H}_{\\rm total}(t) = \\hat{H}_{\\rm drift} + \\hat{H}_{\\rm ctrl }(t) .\n",
    "$$\n",
    "\n",
    "我们从一个具有三能级的单量子比特系统开始，该系统的哈密顿量可以写成：\n",
    "\n",
    "$$\n",
    "\\hat{H} = \\alpha_q \\hat{a}^{\\dagger}\\hat{a}^{\\dagger}\\hat{a}\\hat{a} + \\frac{1}{2} c(t) \\cos(\\phi) (\\hat{a}+\\hat{a}^{\\dagger}).\n",
    "$$\n",
    "\n",
    "这里，$\\alpha_q$ 是量子比特第 0 到第 1 能级和第 1 到第 2 能级的跃迁能量之间的失谐性；$c(t)$ 表示脉冲包络函数；而 $\\phi$ 是脉冲相位。$\\hat{a}^{\\dagger}=|1\\rangle\\langle 0|+\\sqrt{2}|2\\rangle\\langle 1|$ 和 $\\hat{a}=|0\\rangle\\langle 1|+\\sqrt{2}|1\\rangle\\langle 2|$ 分别是产生和湮灭算符。\n",
    "\n",
    "用户可以使用量脉中的 `QHamiltonian` 模块方便地定义多量子比特系统的哈密顿量。接下来，我们将演示如何使用量脉定义上面的哈密顿量。首先，我们初始化系统哈密顿量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham = QHam(subSysNum=1, sysLevel=3, dt=0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的 `QHam()` 函数返回一个初始化的哈密顿量，它的参数包括量子比特的数量及其能级数量，采样频率等。\n",
    "\n",
    "然后我们可以利用 `addDrift()` 函数将漂移项的算符添加到哈密顿量中，该函数的参数中包括一个 `QHam` 对象 `ham`、相应的算符（我们在 `QOperator` 中包含了许多常用的算符）、算符所作用的量子位索引以及振幅系数 `coef`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alphaQ = - 0.22 * (2 * pi)  # unit is GHz\n",
    "ham.addDrift(duff, 0, coef=alphaQ)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里，我们使用 `QOperator` 模块中的 `duff(n)` 函数来定义 $n$ 维的 $\\hat{a}^{\\dagger}\\hat{a}^{\\dagger}\\hat{a}\\hat{a}$；然后，用户可以使用 `print()` 函数来显示哈密顿量的属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(ham)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来，我们通过 `addWave()` 将控制项添加到先前我们定义好的哈密顿量中。与之前版本的量脉相比，我们更新了通过同时添加算符及其相应波形来添加控制脉冲的策略。在这里，我们需要加脉冲项：\n",
    "\n",
    "$$\n",
    "c(t) = A e^{-(t-\\tau)^2/2\\sigma^2}.\n",
    "$$\n",
    "\n",
    "我们需要向 `addWave()` 输入控制项算符 `driveX()`，目标量子位索引及其波形（量脉支持多个波形的定义）以及所定义波形所需的参数： "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham.appendWave(driveX, 0, gaussian(t=20, a=1.0, tau=10.0, sigma=3.0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "目前为止，我们定义了一个完整的量子系统和控制该系统的相关参数。我们可以使用 `plot()` 来可视化哈密顿量中 `QJob` 的脉冲任务。该函数还包括一个可选的 bool 参数 `dark`，用于启用暗色模式。此外，用户还可以使用 `color` 参数为脉冲指定颜色（如果脉冲数多于颜色数，则颜色将重复使用）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham.job.plot(dark=True, color=['mint'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后我们可以使用 `simulate()` 函数来模拟相应系统的演化，并获得系统的酉矩阵的时间演化："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = ham.simulate(recordEvolution=False)\n",
    "result.result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 脉冲扫描\n",
    "\n",
    "\n",
    "在脉冲时间 $t_g$ 固定的情况下，我们可以扫描脉冲的振幅 $a$，找到相应 $\\pi$ 脉冲的振幅 $a_{\\pi}$ 。\n",
    "\n",
    "\n",
    "我们首先创建一个含有 200 个点的等间距的列表（ -1 到 1 之间），用于表示脉冲的振幅。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initilize the pulse's amplitudes\n",
    "aList = linspace(-1.0, 1.0, 200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后，通过模拟上一节我们定义的哈密顿量的时间演化，我们可以得到每个态的时间演化。在本地设备上进行酉矩阵的演化运算通常需要很长时间，但是我们可以通过量脉云服务来加快这一过程。要使用量脉云服务，用户需要从 http://quantum-hub.baidu.com 获取一个 token 从而将任务提交到量脉的服务器。量脉支持批量任务的提交处理，这可以进一步优化资源的分配。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Calibrate a Pi Pulse\n",
    "jobList = ham.createJobList()\n",
    "for a in aList:\n",
    "    # Configure pulse parameters\n",
    "    job = jobList.createJob()\n",
    "    job.appendWave(driveX, 0, gaussian(20, a=a, tau=10, sigma=3))\n",
    "    jobList.addJob(job)\n",
    "\n",
    "# Import Define class and set the token\n",
    "# Please visit http://quantum-hub.baidu.com\n",
    "from Quanlse import Define\n",
    "Define.hubToken = \"\"\n",
    "\n",
    "# Submit batch jobs to Quanlse Cloud Service\n",
    "resultList = runHamiltonian(ham, jobList=jobList)\n",
    "\n",
    "# Calculate populations\n",
    "pop0List = []\n",
    "pop1List = []\n",
    "pop2List = []\n",
    "for result in resultList:\n",
    "    finalState = dot(result[\"unitary\"], array([1, 0, 0], dtype=complex))\n",
    "    pop0List.append(abs(finalState[0])**2)\n",
    "    pop1List.append(abs(finalState[1])**2)\n",
    "    pop2List.append(abs(finalState[2])**2)\n",
    "\n",
    "# Plot graph\n",
    "plt.plot(aList, pop0List, label=\"Ground state\")\n",
    "plt.plot(aList, pop1List, label=\"1st excited state\")\n",
    "plt.plot(aList, pop2List, label=\"2nd excited state\")\n",
    "plt.xlabel(\"Amplitude\")\n",
    "plt.ylabel(\"Population of different states\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 余弦拟合\n",
    "\n",
    "现在我们获得了一组离散的点，要找到 $\\pi$ 脉冲的振幅，我们需要用余弦函数拟合这些点。为了拟合 $|0\\rangle$ 态的时间演化，我们使用 `Scipy` 中的 `optimize.curve_fit()` 函数。我们首先定义以下函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fit_function(xValues, yValues, initParams):\n",
    "    def fit_func(x, A, B, period, phi):\n",
    "        return A * cos(2 * pi * x / period - phi) + B\n",
    "    fitParams, _ = curve_fit(fit_func, xValues, yValues, initParams, bounds=(0, [2.0, 2.0, 2.0, 2.0]), method='dogbox')\n",
    "    yFit = fit_func(xValues, *fitParams)\n",
    "    return fitParams, yFit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "然后我们使用回归函数得到结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "fitParams, yFit = fit_function(aList, pop0List, [0.5, 0.5, 0.8, 0])\n",
    "\n",
    "# Plot graph\n",
    "plt.scatter(aList, pop0List, label=\"Samples\")\n",
    "plt.plot(aList, yFit, color=\"red\", label=\"Fit curve\")\n",
    "plt.xlabel(\"Amplitude\")\n",
    "plt.ylabel(\"Population of ground state\")\n",
    "plt.legend()\n",
    "plt.show()\n",
    "print(f\"Period is {fitParams[2]}\")\n",
    "print(f\"Pi pulse amplitude is {fitParams[2] / 2}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过余弦回归，我们确定了 $\\pi$ 脉冲的相应振幅约为0.42。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "source": [
    "## 总结\n",
    "\n",
    "在阅读完这篇有关校准 $\\pi$ 脉冲的教程后，用户可以通过这个链接 [tutorial-calibrate-pi-pulses.ipynb](https://github.com/baidu/Quanlse/blob/main/Tutorial/CN/tutorial-pi-pulse-cn.ipynb) 跳转到此 Jupyter Notebook 文档相应的 GitHub 页面获得相关代码。我们鼓励用户尝试不同于本教程的参数值以更好地理解如何使用量脉。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
